﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApp
{
    public class Enumerables
    {
        public void Show()
        {
            //_Aggregate();
            //_Except();
            //_GroupBy();
            //_GroupJoin();
            //_Intersect();
            //_Join();
        }

        private void _Aggregate()
        {
            string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };

            //确定数组中是否有任何字符串长于“banana”。
            string longestName =
                fruits.Aggregate("banana",
                                (longest, next) =>
                                    next.Length > longest.Length ? next : longest,
                                //以大写字符串形式返回最终结果。
                                fruit => fruit.ToUpper());

            Console.WriteLine(
                "The fruit with the longest name is {0}.",
                longestName);

            //此代码生成以下输出：
            //
            // The fruit with the longest name is PASSIONFRUIT.
        }

        private void _AsEnumerable()
        {
            IEnumerable<Student> students = AppDBData.GetDBStudents();
            var students2 = students.AsEnumerable();
        }

        private void _Except()
        {


            #region 由此可以发现没有比较器，去除不了fruits2,比较的是地址
            {
                //Console.WriteLine("--由此可以发现没有比较器，去除不了fruits2--");
                //Product[] fruits1 = {
                //new Product { Name = "apple", Code = 9 },
                //new Product { Name = "orange", Code = 4 },
                //new Product { Name = "lemon", Code = 12 }
                //};

                //Product[] fruits2 = { new Product { Name = "apple", Code = 9 } };
                //var excepts = fruits1.Except(fruits2);
                //var ator = excepts.GetEnumerator();
                //while (ator.MoveNext())
                //{
                //    Console.WriteLine($"{ator.Current.Name}:{ator.Current.Code}");
                //}

                //Console.WriteLine("--以下证明排除是根据内存地址进行排除的--");
                //var productItem1 = new Product() { Name = "lemon", Code = 12 };
                //var fruits3 = new Product[] { new Product { Name = "apple", Code = 9 }, productItem1 };
                //var fruits4= new Product[] { new Product { Name = "apple", Code = 9 }, productItem1 };
                //var excepts = fruits3.Except(fruits4);
                //foreach (var item in excepts)
                //{
                //    Console.WriteLine($"{item.Name}:{item.Code}");
                //}
            }
            #endregion

            #region 这种就可以了(实现了IEquatable,重写(指定)新的equat,和hashcode)

            //Console.WriteLine("----这种就可以了(实现了IEquatable,重写(指定)新的equat,和hashcode)-----");
            //{
            //    ProductA[] fruits1 = {
            //    new ProductA { Name = "apple", Code = 9 },
            //    new ProductA { Name = "orange", Code = 4 },
            //    new ProductA { Name = "lemon", Code = 12 }
            //    };

            //    ProductA[] fruits2 = {
            //        new ProductA { Name = "apple", Code = 9 },
            //        new ProductA { Name = "banana", Code = 18 } };
            //    var excepts = fruits1.Except(fruits2);
            //    var ator = excepts.GetEnumerator();
            //    while (ator.MoveNext())
            //    {
            //        Console.WriteLine($"{ator.Current.Name}:{ator.Current.Code}");
            //    }
            //}
            #endregion

            #region IEqualityComparer<TSource>
            Console.WriteLine("----这种也可以了IEqualityComparer<TSource>-----");

            {
                Product[] fruits1 = {
                new Product { Name = "apple", Code = 9 },
                new Product { Name = "orange", Code = 4 },
                new Product { Name = "lemon", Code = 12 }
                };

                Product[] fruits2 = { new Product { Name = "apple", Code = 9 } };

                var excepts = fruits1.Except(fruits2, new ProductEqualityComparer());
                foreach (var item in excepts)
                {
                    Console.WriteLine($"{item.Name}:{item.Code}");
                }
                #endregion
            }


        }

        public class Product
        {
            public string Name { get; set; }
            public int Code { get; set; }
        }

        public class ProductA : IEquatable<ProductA>
        {
            public string Name { get; set; }
            public int Code { get; set; }

            public bool Equals(ProductA other)
            {
                if (other == null)
                    return false;
                return Name == other.Name && Code == other.Code;
            }
            public override bool Equals(object obj) => Equals(obj as ProductA);
            public override int GetHashCode() => (Name, Code).GetHashCode();
        }

        public class ProductEqualityComparer : IEqualityComparer<Product>
        {
            public bool Equals(Product x, Product y)
            {
                if (Object.ReferenceEquals(x, y))
                    return true;
                if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                    return false;
                return x.Name == y.Name && x.Code == y.Code;
            }

            public int GetHashCode(Product product)
            {
                //Check whether the object is null
                if (Object.ReferenceEquals(product, null)) return 0;

                //Get hash code for the Name field if it is not null.
                int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();

                //Get hash code for the Code field.
                int hashProductCode = product.Code.GetHashCode();

                //Calculate the hash code for the product.
                return hashProductName ^ hashProductCode;
            }
        }


        private void _GroupBy()
        {
            {
                //List<Pet> petsList = new List<Pet>{
                //       new Pet { Name="Barley", Age=8.3 },
                //       new Pet { Name="Boots", Age=4.9 },
                //       new Pet { Name="Whiskers", Age=1.5 },
                //       new Pet { Name="Daisy", Age=4.3 }
                //    };

                //var query = petsList.GroupBy(
                //        pet => Math.Floor(pet.Age),
                //        pet => pet.Age,
                //        (baseAge, ages) => new
                //        {
                //            Key = baseAge,
                //            Count = ages.Count(),
                //            Min = ages.Min(),
                //            Max = ages.Max()
                //        });
                //foreach (var result in query)
                //{
                //    Console.WriteLine("\nAge group: " + result.Key);
                //    Console.WriteLine("Number of pets in this age group: " + result.Count);
                //    Console.WriteLine("Minimum age: " + result.Min);
                //    Console.WriteLine("Maximum age: " + result.Max);
                //}
            }

            {
                List<PetA> pets = new List<PetA>{
                       new PetA { Name="Barley", Age=8 },
                       new PetA { Name="Boots", Age=4 },
                       new PetA { Name="Whiskers", Age=1 },
                       new PetA { Name="Daisy", Age=4 } };

                IEnumerable<IGrouping<int, string>> query =
                    pets.GroupBy(pet => pet.Age, pet => pet.Name);

                foreach (IGrouping<int, string> petGroup in query)
                {
                    Console.WriteLine(petGroup.Key);
                    foreach (string name in petGroup)
                        Console.WriteLine("  {0}", name);
                }
            }
        }

        class Pet
        {
            public string Name { get; set; }
            public double Age { get; set; }
        }
        class PetA
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }


        private void _GroupJoin()
        {
            Person magnus = new Person { Name = "Hedlund, Magnus" };
            Person terry = new Person { Name = "Adams, Terry" };
            Person charlotte = new Person { Name = "Weiss, Charlotte" };

            PetB barley = new PetB { Name = "Barley", Owner = terry };
            PetB boots = new PetB { Name = "Boots", Owner = terry };
            PetB whiskers = new PetB { Name = "Whiskers", Owner = charlotte };
            PetB daisy = new PetB { Name = "Daisy", Owner = magnus };

            List<Person> peoples = new List<Person> { magnus, terry, charlotte };
            List<PetB> pets = new List<PetB> { barley, boots, whiskers, daisy };

            var query = peoples.GroupJoin(pets, people => people, pet => pet.Owner, (people, listPet) => new
            {
                people.Name,
                listPetName = listPet.Select(s => s.Name)
            });
            foreach (var item in query)
            {
                Console.WriteLine(item.Name);
                foreach (var petName in item.listPetName)
                {
                    Console.WriteLine("   " + petName);
                }
            }


        }
        class Person
        {
            public string Name { get; set; }
        }

        class PetB
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        private void _Intersect()
        {
            //使用比较器
            {
                //Product[] store1 = { new Product { Name = "apple", Code = 9 },
                //       new Product { Name = "orange", Code = 4 } };

                //Product[] store2 = { new Product { Name = "apple", Code = 9 },
                //       new Product { Name = "lemon", Code = 12 } };
                //var intersects = store1.Intersect(store2, new ProductEqualityComparer());
                //foreach (var item in intersects)
                //{
                //    Console.WriteLine(item.Name);
                //}
            }
            //使用类自身实现IEquatable
            {
                ProductA[] store1 = { new ProductA { Name = "apple", Code = 9 },
                       new ProductA { Name = "orange", Code = 4 } };

                ProductA[] store2 = { new ProductA { Name = "apple", Code = 9 },
                       new ProductA { Name = "lemon", Code = 12 } };
                var intersects = store1.Intersect(store2);
                foreach (var item in intersects)
                {
                    Console.WriteLine(item.Name);
                }
            }
        }

        private void _Join()
        {
            Person magnus = new Person { Name = "Hedlund, Magnus" };
            Person terry = new Person { Name = "Adams, Terry" };
            Person charlotte = new Person { Name = "Weiss, Charlotte" };

            PetB barley = new PetB { Name = "Barley", Owner = terry };
            PetB boots = new PetB { Name = "Boots", Owner = terry };
            PetB whiskers = new PetB { Name = "Whiskers", Owner = charlotte };
            PetB daisy = new PetB { Name = "Daisy", Owner = magnus };

            List<Person> peoples = new List<Person> { magnus, terry, charlotte };
            List<PetB> pets = new List<PetB> { barley, boots, whiskers, daisy };
            var query = peoples.Join(pets, person => person, pet => pet.Owner,
                (person, pet) => new
                {
                    OwnerName = person.Name,
                    PetName = pet.Name
                });
            foreach (var obj in query)
            {
                Console.WriteLine(
                    "{0} - {1}",
                    obj.OwnerName,
                    obj.PetName);
            }
        }
    }
}
